package com.phenix.network.response

import com.phenix.network.base.Envelope
import com.phenix.network.error.BusinessException
import com.squareup.moshi.*
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

class MoshiResultTypeAdapterFactory(private val envelope: Envelope?) : JsonAdapter.Factory {


    override fun create(
        type: Type,
        annotations: MutableSet<out Annotation>,
        moshi: Moshi
    ): JsonAdapter<*>? {
        val rawType = type.rawType

        if (rawType != NetworkResponse::class.java) return null

        val dataType: Type =
            (type as? ParameterizedType)?.actualTypeArguments?.firstOrNull() ?: return null

        val dataTypeAdapter = moshi.nextAdapter<Any>(this, dataType, annotations)

        return ResultTypeAdapter(dataTypeAdapter, envelope)
    }


    class ResultTypeAdapter<T>(
        private val dataTypeAdapter: JsonAdapter<T>,
        private val envelope: Envelope?
    ) : JsonAdapter<T>() {
        override fun fromJson(reader: JsonReader): T? {
            if (envelope != null) {
                reader.beginObject()
                var errorCode: Int? = null
                var msg: String? = null
                var data: T? = null
                while (reader.hasNext()) {
                    when(reader.nextName()) {
                        envelope.getStatusCodeKey() -> errorCode = reader.nextString().toIntOrNull()
                        envelope.getErrorMessageKey() -> msg = reader.nextString()
                        envelope.getDataKey() -> data = dataTypeAdapter.fromJson(reader)
                        else -> reader.skipValue()
                    }
                }
                reader.endObject()
                if (errorCode == null) {
                    throw JsonDataException("Expected field  [errorCode] not present.")
                }

                return if (envelope.doesStatusCodeIndicateSuccess(errorCode)) data
                else throw BusinessException(errorCode, msg)
            }
            return dataTypeAdapter.fromJson(reader)
        }

        override fun toJson(writer: JsonWriter, value: T?) {
            TODO("Not yet implemented")
        }

    }
}
